#include "CTcpAcceptorImpl.h"
#include "CNetService.h"
#include "CNetServiceImpl.h"
#include "CTcpSocket.h"
#include "CUtil.h"

namespace TB
{
	CTcpAcceptorImpl::CTcpAcceptorImpl()
	{
#if _WIN32
        m_nAcceptorFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#else
		m_nAcceptorFD = socket(AF_INET, SOCK_STREAM, 0);
#endif
	}

	CTcpAcceptorImpl::~CTcpAcceptorImpl()
	{
        Close();
	}

	bool CTcpAcceptorImpl::Init(const std::weak_ptr<CNetService>& poNetService, const std::weak_ptr<CTcpAcceptorImpl>& poSelf)
	{
        if (!m_poNetService.expired())
            return false;
        m_poNetService = poNetService;
        m_poSelf = poSelf;
        return true;
	}

    bool CTcpAcceptorImpl::SetReuseAddr(bool bReuse)
    {
        if (m_nAcceptorFD == INVALID_SOCKET)
            return false;
        int rep = bReuse ? 1 : 0;
        return 0 == setsockopt(m_nAcceptorFD, SOL_SOCKET, SO_REUSEADDR, (const char*)&rep, sizeof(rep));
    }

	ENetErrorCode CTcpAcceptorImpl::Listen(UINT32 dwIP, UINT16 wPort, UINT32 dwBacklog) //主机字节序
    {
        if (m_nAcceptorFD == INVALID_SOCKET)
            return ENetErrorCode::NotSocket;
        if (!SetNonBlock(m_nAcceptorFD))
            return ENetErrorCode::SocketError;
#if _WIN32
        sockaddr_in oListenedAddr = {};
        oListenedAddr.sin_family = AF_INET;
        oListenedAddr.sin_port = htons(wPort);
        oListenedAddr.sin_addr.s_addr = htonl(dwIP);
        int error = bind(m_nAcceptorFD, (SOCKADDR*)&oListenedAddr, sizeof(SOCKADDR));
#else
        sockaddr_in oListenedAddr = {};
        oListenedAddr.sin_family = AF_INET;
        oListenedAddr.sin_port = htons(wPort);
        oListenedAddr.sin_addr.s_addr = htonl(dwIP);
        int error = bind(m_nAcceptorFD, (sockaddr*)&oListenedAddr, sizeof(sockaddr_in));
#endif
        if (error == SOCKET_ERROR)
        {
            return GetLastError();
        }
        error = listen(m_nAcceptorFD, dwBacklog);//会被/proc/sys/net/core/somaxconn限制
        if (error == SOCKET_ERROR)
        {
            return GetLastError();
        }
        return ENetErrorCode::Success;
	}

	void CTcpAcceptorImpl::Accept(STaskProcessor<std::pair<ENetErrorCode, std::shared_ptr<CTcpSocket>>>& sTaskProcessor)
	{
        m_oAcceptTaskQueue.emplace_back(sTaskProcessor);
        if (m_oAcceptTaskQueue.size() == 1)
            _Accept();
	}

    void CTcpAcceptorImpl::_Accept()
    {
        while (!m_oAcceptTaskQueue.empty())
        {
            ENetErrorCode eNetErrorCode = ENetErrorCode::Success;
            SOCKET nSocketFD = INVALID_SOCKET;
            do
            {
                nSocketFD = accept(m_nAcceptorFD, NULL, 0);
            } while (nSocketFD == INVALID_SOCKET && (eNetErrorCode = GetLastError()) == ENetErrorCode::Interrupted);
            if (nSocketFD == INVALID_SOCKET)
            {
                if (eNetErrorCode != ENetErrorCode::TryAgain && eNetErrorCode != ENetErrorCode::WouldBlock)
                {
                    _RemovePoll();
                    while (!m_oAcceptTaskQueue.empty())
                    {
                        auto& sProcessor = m_oAcceptTaskQueue.front();
                        sProcessor.Resolve({ eNetErrorCode, nullptr });
                        m_oAcceptTaskQueue.pop_front();
                    }
                    return;
                }
                if (!_AddPoll())
                {
                    while (!m_oAcceptTaskQueue.empty())
                    {
                        m_oAcceptTaskQueue.front().Resolve({ ENetErrorCode::OperationAborted, nullptr });
                        m_oAcceptTaskQueue.pop_front();
                    }
                }
                return;
            }
            m_oAcceptTaskQueue.front().Resolve({ ENetErrorCode::Success, std::shared_ptr<CTcpSocket>(new CTcpSocket(nSocketFD)) });
            m_oAcceptTaskQueue.pop_front();
        }
#if _WIN32
        _RemovePoll();
#endif
    }

    bool CTcpAcceptorImpl::_AddPoll()
    {
        if (IsClosed())
            return false;
        auto poNetService = m_poNetService.lock();
        if (!poNetService)
            return false;
        if (m_bAddedToPoll)
            return true;
        m_bAddedToPoll = true;
        auto poWeakPtr = m_poSelf;
#if _WIN32
        bool bAddFDRet = poNetService->GetImpl()->AddFD(m_nAcceptorFD, POLLRDNORM, [poWeakPtr](SOCKET, SHORT nReturnEvents)
#else
        bool bAddFDRet = poNetService->GetImpl()->AddFD(m_nAcceptorFD, EPOLLIN | EPOLLERR | EPOLLET, [poWeakPtr](SOCKET, UINT32 nReturnEvents)
#endif
        {
            auto poSelf = poWeakPtr.lock();
            if (poSelf == nullptr || poSelf->IsClosed())
                return;
            CTcpAcceptorImpl& roSelf = *poSelf;
#if _WIN32
            if ((nReturnEvents & POLLERR) != 0)
#else
            if ((nReturnEvents & EPOLLERR) != 0)
#endif
            {
                ENetErrorCode eNetErrorCode = GetLastError();
                while (!roSelf.m_oAcceptTaskQueue.empty())
                {
                    auto& rsProcessor = roSelf.m_oAcceptTaskQueue.front();
                    rsProcessor.Resolve({ eNetErrorCode, nullptr });
                    roSelf.m_oAcceptTaskQueue.pop_front();
                }
                return;
            }
#if _WIN32
            if ((nReturnEvents & POLLRDNORM) != 0)
#else
            if ((nReturnEvents & EPOLLIN) != 0)
#endif
            {
                roSelf._Accept();
            }
        });
        if (!bAddFDRet)
        {
            m_bAddedToPoll = false;
            return false;
        }
        return true;
    }
    
    bool CTcpAcceptorImpl::_RemovePoll()
    {
        if (IsClosed())
            return false;
        auto poNetService = m_poNetService.lock();
        if (!poNetService)
            return false;
        if (!m_bAddedToPoll)
            return true;
        m_bAddedToPoll = false;
        if (!poNetService->GetImpl()->DelFD(m_nAcceptorFD))
        {
            m_bAddedToPoll = true;
            return false;
        }
        return true;
    }

    bool CTcpAcceptorImpl::GetLocalIpPort(std::pair<UINT32, UINT16>& roIpPort) const //主机字节序
    {
        if (m_nAcceptorFD == INVALID_SOCKET)
        {
            return false;
        }
        struct sockaddr_in addr;
#if _WIN32
        int addr_len = sizeof(addr);
#else
        socklen_t addr_len = sizeof(addr);
#endif
        if (0 == getsockname(m_nAcceptorFD, (struct sockaddr*)&addr, &addr_len))
        {
            roIpPort = { (UINT32)ntohl(addr.sin_addr.s_addr), (UINT16)ntohs(addr.sin_port) };
            return true;
        }
        return false;
    }

	bool CTcpAcceptorImpl::IsClosed() const
	{
        return m_nAcceptorFD == INVALID_SOCKET;
	}

	void CTcpAcceptorImpl::Close()
	{
        if (IsClosed())
            return;
        auto poNetService = m_poNetService.lock();
        if (!poNetService)
            return;
        if (m_nAcceptorFD != INVALID_SOCKET)
        {
            if (m_bAddedToPoll)
            {
                if (0 == poNetService->GetImpl()->DelFD(m_nAcceptorFD))
                    m_bAddedToPoll = false;
            }
#if _WIN32
            closesocket(m_nAcceptorFD);
#else
            close(m_nAcceptorFD);
#endif
        }
        m_nAcceptorFD = INVALID_SOCKET;
        while (!m_oAcceptTaskQueue.empty())
        {
            m_oAcceptTaskQueue.front().Resolve({ ENetErrorCode::OperationAborted, nullptr });
            m_oAcceptTaskQueue.pop_front();
        }
	}
}